package org.tio.sitexxx.service.service.stat;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import org.tio.sitexxx.service.cache.CacheConfig;
import org.tio.sitexxx.service.cache.Caches;
import org.tio.sitexxx.service.model.main.ChatRecord;
import org.tio.sitexxx.service.model.main.ChatRecordP2p;
import org.tio.sitexxx.service.model.main.IpInfo;
import org.tio.sitexxx.service.model.main.User;
import org.tio.sitexxx.service.service.base.IpInfoService;
import org.tio.sitexxx.service.service.base.UserService;
import org.tio.sitexxx.service.service.conf.ConfService;
import org.tio.sitexxx.service.vo.Const;
import org.tio.utils.cache.CacheUtils;
import org.tio.utils.cache.FirsthandCreater;
import org.tio.utils.cache.ICache;
import org.tio.utils.lock.ListWithLock;
import org.tio.utils.lock.WriteLockHandler;

import com.jfinal.kit.Kv;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;

/**
 * 聊天日志
 * @author tanyaowu
 *
 */
public class ChatRecordP2PService {

	//	private static Logger log = LoggerFactory.getLogger(ChatRecordService.class);

	public static final ChatRecordP2PService me = new ChatRecordP2PService();

	static final ChatRecordP2p dao = new ChatRecordP2p().dao();

	//	static final ICache groupChatRecordCache = Caches.getCache(CacheConfig.GROUP_CHAT_LOG);

	static final ICache P2P_CHATRECORD_CACHE = Caches.getCache(CacheConfig.P2P_CHAT_LOG);
	static final ICache N2P_NOT_READ_COUNT_CACHE = Caches.getCache(CacheConfig.N2P_NOT_READ_COUNT);
	static final ICache N2P_LATELY_COUNT_CACHE = Caches.getCache(CacheConfig.N2P_LATELY_COUNT);
	
	

	//	static final int DEFAULT_HISTORY_CHAT_COUNT_GROUP = 200;

	static final int DEFAULT_HISTORY_CHAT_COUNT_P2P = 200;

	private ChatRecordP2PService() {
	}

	//	public void addToQueue(ChatRecord chatRecord) {
	//		ChatRecordRunnable.me.addMsg(chatRecord);
	//		ChatRecordRunnable.me.execute();
	//		putToGroupCache(chatRecord);
	//	}
	//	
	public boolean save(ChatRecordP2p chatRecordP2p) {
		chatRecordP2p.setTwouid(Math.max(chatRecordP2p.getUid(), chatRecordP2p.getTouid()) + "_" + Math.min(chatRecordP2p.getUid(), chatRecordP2p.getTouid()));
		if (Objects.equals(chatRecordP2p.getUid(), chatRecordP2p.getTouid())) {
			chatRecordP2p.setReadflag((byte) 1);  //自己发给自己，则自动标识为已读
		}
		
		boolean f = chatRecordP2p.save();
		if (f) {
			//			if (StrUtil.isNotBlank(chatRecord.getGroupid())) {
			//				putToGroupCache(chatRecord);
			//			} else {
			putToP2pCache(chatRecordP2p);
			//			}
		}

		return f;
	}

	/**
	 * 
	 * @param sessionid
	 * @param initContent
	 * @param displayContent
	 * @param fromuid
	 * @param fromIp
	 * @param touid
	 * @param contenttype
	 * @return
	 */
	public ChatRecordP2p saveChatRecord(String sessionid, String initContent, String displayContent, Integer fromuid, String fromIp, Integer touid,
	        Byte contenttype) {
		//存聊天日志
		IpInfo ipInfo = IpInfoService.ME.save(fromIp);
		//		RoomInst roomInst = ImServerService.me.getOnLive(groupid);
		ChatRecordP2p chatRecordP2p = new ChatRecordP2p();
		chatRecordP2p.setInput(initContent);
		chatRecordP2p.setText(displayContent);
		chatRecordP2p.setIpid(ipInfo.getId());
		//		if (roomInst != null) {
		//			chatRecord.setRoominstid(roomInst.getId());
		//		}
		chatRecordP2p.setTime(new Date());
		chatRecordP2p.setTouid(touid);
		chatRecordP2p.setUid(fromuid);
		chatRecordP2p.setSession(sessionid);

		chatRecordP2p.setContenttype(contenttype);
		//		chatRecord.setMid(mid);
		chatRecordP2p.setStatus(ChatRecord.Status.OK);
		save(chatRecordP2p);
		return chatRecordP2p;
	}

	/**
	 * 
	 * @param mid
	 * @param status
	 * @author tanyaowu
	 */
	public void updateStatus(String mid, byte status) {
		String sql = "update chat_record_p2p set status = ? where id = ?";
		Db.use(Const.Db.TIO_SITE_MAIN).update(sql, status, Integer.parseInt(mid));
	}

	/**
	 * 将某两人的私聊设置为已读
	 * @param fromuid 私聊的发送人
	 * @param touid 私聊的接收人
	 * @param readdevice 阅读人的设备
	 * @param readipid 阅读人的ip信息
	 */
	public void updateToRead(Integer fromuid, Integer touid, Byte readdevice, Integer readipid) {
		String sql = "update chat_record_p2p set readflag = 1, readtime = ?, readdevice=?, readipid = ? where uid = ? and touid = ? and readflag = 2";
		Db.use(Const.Db.TIO_SITE_MAIN).update(sql, new Date(), readdevice, readipid, fromuid, touid);
		
		String key2 = "" + touid;
		N2P_NOT_READ_COUNT_CACHE.remove(key2);
		
		String key3 = key2;
		N2P_LATELY_COUNT_CACHE.remove(key3);
	}
	
	
	/**
	 * 
	 * @param fromuid
	 * @param touid
	 * @author tanyaowu
	 */
	public void clearP2pChatCache(Integer fromuid, Integer touid) {
		String key = getP2PKey(fromuid, touid);
		P2P_CHATRECORD_CACHE.remove(key);
		
		String key2 = "" + touid;
		N2P_NOT_READ_COUNT_CACHE.remove(key2);
		
		String key3 = key2;
		N2P_LATELY_COUNT_CACHE.remove(key3);
		
	}
	
	

	/**
	 * 根据消息id获取记录
	 * @param mid 消息id (chat_record_p2p的id字段)
	 * @return
	 */
	public ChatRecordP2p getByMid(String mid) {
		String sql = "select * from chat_record_p2p where id = ?";
		return dao.findFirst(sql, Integer.parseInt(mid));
	}
	
	/**
	 * <pre>
	 * c   uid        nick         text             avatar
	 * 55  23352     talent-tan   你好emm      /avatar/wxnv4/2018/03/22/1.jpg
	 * 获取某用户的未读消息数
	 * </pre>
	 * @param touid
	 * @return
	 */
	public List<Record> getNotReadCount(Integer touid) {
		if (touid == null) {
			return null;
		}
		
		String key = "" + touid;
		List<Record> list = CacheUtils.get(N2P_NOT_READ_COUNT_CACHE, key, true, new FirsthandCreater<ArrayList<Record>>() {
			@Override
			public ArrayList<Record> create() {
				Kv params = Kv.by("touid", touid);
				SqlPara sqlPara = Db.use(Const.Db.TIO_SITE_MAIN).getSqlPara("p2p.n2p_notread", params);
				List<Record> list = Db.use(Const.Db.TIO_SITE_MAIN).find(sqlPara);
				completeRecord(list, touid);
				return (ArrayList<Record>)list;
			}
		});
		return list;
	}
	
	/**
	 * 获取发给某用户的私聊，未读的消息放前面，已经读的消息放后面，按时间倒序
	 * @param touid
	 * @return
	 * @author tanyaowu
	 */
	public List<Record> getLastN2pChat(Integer touid) {
		if (touid == null) {
			return null;
		}
		String key = "" + touid;
		List<Record> list = CacheUtils.get(N2P_LATELY_COUNT_CACHE, key, true, new FirsthandCreater<ArrayList<Record>>() {
			@SuppressWarnings("unchecked")
			@Override
			public ArrayList<Record> create() {
				List<Record> list1 = getNotReadCount(touid);
				
				Kv params = Kv.by("touid", touid);
				int limit = 100;
				if (list1 != null && list1.size() > 0) {
					limit = limit - list1.size();
					StringBuilder notInUidStr = new StringBuilder();
					for (Record record : list1) {
						notInUidStr.append(record.getStr("uid")).append(",");
					}
					notInUidStr.setLength(notInUidStr.length() - 1);
					params.put("notInUidStr", notInUidStr);
				}
				
				limit = Math.max(limit, 1);
				params.put("limit", limit);
				
				SqlPara sqlPara = Db.use(Const.Db.TIO_SITE_MAIN).getSqlPara("p2p.n2p_read", params);
				List<Record> list2 = Db.use(Const.Db.TIO_SITE_MAIN).find(sqlPara);
				completeRecord(list2, touid);
				
				if (list1 != null && list1.size() > 0) {
					list1.addAll(list2);
					return (ArrayList<Record>)list1;
				} else {
					return (ArrayList<Record>)list2;
				}
				
			}
		});
		
		return list;
	}
	
	private void completeRecord(List<Record> list, int fortouid) {
		if (list != null && list.size() > 0) {
			for (Record record : list) {
				Integer uid = record.getInt("uid");
				Integer touid = record.getInt("touid");
				
				if (!Objects.equals(uid, touid) && Objects.equals(fortouid, uid)) {
					uid = touid;
					record.set("uid", touid);
				}
				
				User user = UserService.ME.getById(uid);
				record.set("nick", user.getNick());
				record.set("avatar", user.getAvatar());
				record.set("roles", user.getRoles());
			}
		}
	}

	/**
	 * 获取俩人最近的私聊记录，用于私聊框显示
	 * @param uid1
	 * @param uid2
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public ListWithLock<ChatRecordP2p> getLastP2pChat(Integer uid1, Integer uid2) {
		if (uid1 == null || uid2 == null) {
			return null;
		}

		String key = getP2PKey(uid1, uid2);
		ListWithLock<ChatRecordP2p> listWithLock = CacheUtils.get(P2P_CHATRECORD_CACHE, key, true, new FirsthandCreater<ListWithLock<ChatRecordP2p>>() {
			@Override
			public ListWithLock<ChatRecordP2p> create() {
				int historyCount = ConfService.getInt("im.history.chat.count.p2p", DEFAULT_HISTORY_CHAT_COUNT_P2P);
				String sql = "select * from chat_record_p2p where ((touid = ? and uid = ?) or (touid = ? and uid = ?)) and status = 1 order by id desc limit ?";
				ArrayList<ChatRecordP2p> list = (ArrayList<ChatRecordP2p>) dao.find(sql, uid1, uid2, uid2, uid1, historyCount);
				return new ListWithLock(list);
			}
		});
		return listWithLock;
	}

	/**
	   * 添加到p2p cache
	   * @param chatRecord
	   */
	public void putToP2pCache(ChatRecordP2p chatRecord) {
		Integer uid = chatRecord.getUid();
		Integer touid = chatRecord.getTouid();

		String key = getP2PKey(uid, touid);
		if (key != null) {
			@SuppressWarnings("unchecked")
			ListWithLock<ChatRecordP2p> listWithLock = P2P_CHATRECORD_CACHE.get(key, ListWithLock.class);
			if (listWithLock != null) {
				listWithLock.handle(new WriteLockHandler<List<ChatRecordP2p>>() {
					@Override
					public void handler(List<ChatRecordP2p> list) {
						list.add(0, chatRecord);
						int historyCount = ConfService.getInt("im.history.chat.count.p2p", DEFAULT_HISTORY_CHAT_COUNT_P2P);
						while (list.size() > historyCount) {
							list.remove(historyCount);
						}
					}
				});
			}
			
			//下面这个直接清空缓存，对性能影响不大
			String key2 = "" + touid;
			N2P_NOT_READ_COUNT_CACHE.remove(key2);
			
			String key3 = key2;
			N2P_LATELY_COUNT_CACHE.remove(key3);
		}
	}

	public static String getP2PKey(Integer uid1, Integer uid2) {
		return Math.max(uid1, uid2) + "_" + Math.min(uid1, uid2);
	}

}
